from django.http import HttpResponse, HttpResponseRedirect
from django.utils import simplejson
from nerdbot.cards.models import Index_card, Tag, Variable, Restriction
from django.template import Context, loader
from django.http import Http404
from django.shortcuts import render_to_response
from django.db.models import Q

def Denary2Binary(n):  #this is used with all_permutations, explanation below
    '''convert denary (base 10) integer n to binary string bStr'''
    bStr = ''
    if n < 0:  raise ValueError, "must be a positive"
    if n == 0: return '0'
    while n > 0:
        bStr = str(n % 2) + bStr
        n = n >> 1
    return bStr

def all_permutations(list): 
	'''This is used to cycle through every binary representation, starting with a string of 1s as long as the variable list
	Doing binary decrements on this number, and taking the variables on the list that correspond to the 1s, ensures that
	there is a sublist with each combination of variables.
	'''
	all_lists = []
	iterations = 2**(len(list)) - 1 #creates the big list of 1s
	for i in range(iterations+1):
		binary = Denary2Binary(int(i))
		binary = binary[::-1] #inverts the list, since python starts counting from the highest digit, and drops leading zeros
		sublist = []
		for digit_index in range(len(binary)):
			if binary[digit_index] == '1': sublist.append(list[digit_index])
		all_lists.append(sublist)
	return all_lists[1:] #the first list is always empty

def ajax(request):
	tagquery = 'tagquery'
	if request.POST: #if there is a request
		tagquery_request = request.POST.get('query')
		tagquery = tagquery_request.split()
		restrictions_request = request.POST.get('restrict')
		restrictions = str(restrictions_request).split()
		search_type_request = request.POST.get('search_type')
	if search_type_request == 'matt':
		constraints = []
		variables = []
		search_results = []
		unrecognized_variables = []
		recognized_variables = []

		search_results_list = []
		restriction_set = []
		tagquery_request = []
		restrictions = []

		for t in tagquery:
			if Variable.objects.filter(name = t):  #catches full variable names and adds their symbols to the search
				tagquery.append(Variable.objects.filter(name = t)[0].symbol)
				recognized_variables.append(Variable.objects.filter(name = t)[0])
			elif Variable.objects.filter(symbol = t):
				variables.append(t)
				recognized_variables.append(Variable.objects.filter(symbol = t)[0])
			else: #I'll display a list of search terms that were not recongized.  Maybe add suggestions later?
				suggestion_list = Variable.objects.filter(Q(name__icontains=t) | Q(symbol__icontains=t))
				#suggestion_set = set(suggestion_list)
				unrecognized_variables.append([t, suggestion_list])
		complete_variables_list = variables #This will go to the Template
		variable_lists = all_permutations(variables) #This is where the magic happens.  variable_lists includes every possible combo of the variables (as sub lists)
		
		if (variable_lists or unrecognized_variables):
			for variable_list in variable_lists:
				q = Index_card.objects.all()  #Don't worry, this doesn't resolve until I call q
				for variable in variable_list:
					q = q.filter(variables__symbol = variable) #these are chained, so when it finishes the cycle, only cards with all variables in them are left
				for r in restrictions:
					q= q.exclude(restrictions__name = r)
				list_of_cards_with_all_variables = q #The search finally happens
				
				#We now have a long list of cards which contain some subset of the searched variables
				for card in list_of_cards_with_all_variables:
					symbol_list = []
					for var in card.variables.all():
						symbol_list.append(var.symbol)
					if len(card.variables.all()) == (len(variable_list)+1): #This is the clever part- the card has to have one MORE variable, the one to be solved for
						search_results.append(card)
			search_results = set(search_results) #remove duplicates		
			
			search_results_list = []
			for card in search_results:
				if card.variables.exclude(symbol__in = complete_variables_list): #Exclude cards whose variables are all searched for
					search_results_list.append([card, card.variables.exclude(symbol__in = complete_variables_list)])  #Creates list [card_object, variable_to_solve_for]

			#Restrictions that will be available for leaving out of search
			restriction_list = list()
			for i in search_results_list:
				restriction_list.extend(i[0].restrictions.all())
			restriction_set= set(restriction_list)
			recognized_variables_set = set(recognized_variables)
			
			print search_results_list
			print restriction_set
			print tagquery_request
			print unrecognized_variables
   			print recognized_variables
			print restrictions[1:]
			
			request.session['index_cards'] = search_results_list
			request.session['restriction_set'] = restriction_set
			request.session['unrecognized_variables'] = unrecognized_variables
			request.session['recognized_variables'] = recognized_variables
			request.session['restrictions'] = restrictions
			request.session['tagquery_request'] = tagquery_request
			
			
			return render_to_response('cards/cards2.html', 
							  {'index_cards': search_results_list,
							   'restriction_set': restriction_set,
							   'tagquery':tagquery_request,
							   'unrecognized_variables': unrecognized_variables,
   							   'recognized_variables': recognized_variables,
							   'restrictions': restrictions[1:],
							   })

	else:
		# 'Jay style'
		if tagquery_request:
			tagresults = list()
			for t in tagquery:
			
				tagresults.extend(Tag.objects.filter(name__icontains=t))
			index_card_results2 = list()
			for t in tagresults:
				temp = Index_card.objects.filter(tags__pk=t.pk)
				for r in restrictions:
					temp= temp.exclude(tags__name=r)
				index_card_results2.extend(temp)
			index_card_results2 = list(set(index_card_results2))
			tags = list()
			for i in index_card_results2:
				tags.extend(i.tags.all())
			tags_set= set(tags)
		return render_to_response('cards/cards.html', 
							  {'index_cards': index_card_results2,
							   'tags': tags_set,
							   'tagquery':tagquery_request,
							   'restrictions': restrictions_request,
							   })

def ajax2(request): #just for testing json data transfer. Supposed to be useful
	if request.GET:
		query = request.GET.get('pk')  
	results = {'success':'Hello'}
	results['try']='trial'
	results['pk'] = query
	index_cards = Index_card.objects.all()
	results['index_card'] = 'haha'
	json = simplejson.dumps(results)
	return HttpResponse(json, mimetype='application/json')

def restrict_tag(request):
	if request.POST: #if there is a request
		restrictions = list(request.session['restrictions'])
		restriction_set = list(request.session['restriction_set'])
		new_restriction = Restriction.objects.filter(name = request.POST.get('restrict'))
		restrictions.extend(new_restriction)
		restriction_set.remove(new_restriction[0])
		
		index_cards = request.session['index_cards']
		
			
		new_index_cards = []
		for card in index_cards:
			for restriction in card[0].restrictions.all():
				if not restriction in restrictions:
					new_index_cards.append(card)


		request.session['restrictions'] = restrictions
		request.session['restriction_set'] = restriction_set
		request.session['index_cards'] = new_index_cards
		
		return render_to_response('cards/cards2.html', 
						  {'index_cards': new_index_cards,
						   'restriction_set': restriction_set,
						   'tagquery':request.session['tagquery_request'],
						   'unrecognized_variables': request.session['unrecognized_variables'],
						   'recognized_variables': request.session['recognized_variables'],		
						   'restrictions': restrictions,
						   })
	
def index(request):
	urls = '/nerdbot'
	index_cards = Index_card.objects.all()
	experiment = False
	t = loader.get_template('cards/index.html')
	c = Context({
		'index_cards': index_cards,
		'experiment':experiment,
		'urls':urls
	})
	return HttpResponse(t.render(c))

def misc(request, value):
	#Use this for small popups
	content = 'Content'
	try: 
		content = request.session['fav_color']
	except:
		pass
	if value:
		if value == 'privacy':
			#content = 'Content'
			return render_to_response('cards/misc.html', 
							  {'page':value, 'content':content})
		else:
			return render_to_response('cards/misc.html', 
							  {'page':value})
	else:
		return HttpResponse("Nothing yet")
